package com.aliyun.heiyu.powermaster.server.rotary.service.impl;

import com.alibaba.fastjson.JSON;
import com.aliyun.heiyu.common.util.HttpUtil;
import com.aliyun.heiyu.common.util.PropertiesUtil;
import com.aliyun.heiyu.common.util.StringUtil;
import com.aliyun.heiyu.common.util.ThreadPoolUtil;
import com.aliyun.heiyu.powermaster.proto.ControllRequest;
import com.aliyun.heiyu.powermaster.server.obj.po.VerifyEdgePO;
import com.aliyun.heiyu.powermaster.server.rotary.dao.AirDAO;
import com.aliyun.heiyu.powermaster.server.rotary.dao.AlgorithmDAO;
import com.aliyun.heiyu.powermaster.server.rotary.dao.RecommendDAO;
import com.aliyun.heiyu.powermaster.server.rotary.dao.impl.AirDAOImpl;
import com.aliyun.heiyu.powermaster.server.rotary.dao.impl.AlgorithmDAOImpl;
import com.aliyun.heiyu.powermaster.server.rotary.dao.impl.RecommendDAOImpl;
import com.aliyun.heiyu.powermaster.server.rotary.object.entity.AlgorithmEntity;
import com.aliyun.heiyu.powermaster.server.rotary.object.entity.RecommendEntity;
import com.aliyun.heiyu.powermaster.server.rotary.service.ConnectManager;
import com.aliyun.heiyu.powermaster.server.rotary.service.ModelService;
import com.aliyun.heiyu.powermaster.server.rotary.task.AlgoForecastTask;
import com.aliyun.heiyu.powermaster.server.rotary.task.Task;
import com.aliyun.heiyu.powermaster.server.service.WarningService;
import com.aliyun.heiyu.powermaster.server.service.WarningServiceImpl;
import org.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Map;
import java.util.Set;

/**
 * @Description 模型业务实现
 * @Author shun.zhang
 * @Date 2021/3/12 16:00
 **/
public class ModelServiceImpl implements ModelService {
    private static Logger logger = LoggerFactory.getLogger(ModelServiceImpl.class);
    private AlgorithmDAO algorithmDAO;
    private RecommendDAO recommendDAO;
    private ConnectManager connectManager;
    private WarningService warnService;
    private AirDAO airDAO;
    String aiIp = PropertiesUtil.getValue("serverIp.properties", "aiIp");
    String tempPreUrl = PropertiesUtil.getValue("serverIp.properties", "tempPreUrl");

    public ModelServiceImpl(){
        warnService = new WarningServiceImpl();
        connectManager = new ConnectManagerImpl();
        airDAO = new AirDAOImpl();
        recommendDAO = new RecommendDAOImpl();
        algorithmDAO = new AlgorithmDAOImpl();
    }
    /**
     * 模型预测
     */
    @Override
    public void modelForecast() {
        if(StringUtil.isEmpty(aiIp) || StringUtil.isEmpty(tempPreUrl)){
            logger.info("制冷策略aiIP为空获取ai路径为空");
            return;
        }
        //设置温度上限
        double tempUpper = 0;
        //设置温度下限
        double tempLower = 0;
        //1.查询在使用的算法
        AlgorithmEntity algo = Task.algo;
        //2.查询空调的设置温度上下限
        Map<String, String> air = airDAO.getAirNew();
        //没用空调不执行定时任务
        if(null == air){
            return;
        }
        if(!StringUtil.isEmpty(air.get("air_set_temperature_upper_limit"))){
            tempUpper = Double.valueOf(air.get("air_set_temperature_upper_limit"));
        }else {
            tempUpper = 35;
        }
        if(!StringUtil.isEmpty(air.get("air_set_temperature_lower_limit"))){
            tempLower = Double.valueOf(air.get("air_set_temperature_lower_limit"));
        }else {
            tempLower = 15;
        }
        logger.info("制冷策略 设置温度最大值为:{}  设置温度最小值为:{}",tempUpper,tempLower);
        //3.调制冷算法模块预测空调温度
        double recomTem = getRecomTempByAlgo();
        logger.info("制冷策略预测的温度值为：{}",recomTem);
        if(recomTem == -1){
            return;
        }
        //设置温度等于推荐温度加冷却余量
        double setRecomTem = recomTem + algo.getCooling_allowance();
        logger.info("制冷策略设置的温度值为:{}",setRecomTem);
        airWarn(setRecomTem);
        //4.查询空调动态数据最新的一条数据
        Map<String, String> airTemNew = airDAO.getAirTemNew();
        //5.对比预测温度与采集温度
        if(null == airTemNew){
            return;
        }
        double current = Double.parseDouble(airTemNew.get("room_temperature"));
        //6.保存推荐温度数据到推荐温度表中
        ThreadPoolUtil.execute(new Runnable() {
            @Override
            public void run() {
                saveTem(setRecomTem,current);
            }
        });
        //7.判断设置的空调温度是否在上下限内
        if(setRecomTem>tempUpper || setRecomTem < tempLower){
            logger.info("制冷策略推荐温度不在空调设置限制内 推荐温度:{} 设置上限:{} 设置下限:{}",recomTem,tempUpper,tempLower);
            return;
        }
        //8.如果推荐温度小于采集到的温度调用设置空调温度接口进行调节
        if(current > setRecomTem){
            ThreadPoolUtil.execute(new Runnable() {
                @Override
                public void run() {
                    logger.info("制冷策略通过工控机设置空调温度:[{}]",setRecomTem);
                    setTem(setRecomTem);
                }
            });
        }
    }

    /**
     * 设置空调温度
     * @param tem
     */
    private void setTem(double tem){
        ControllRequest.Builder builder = ControllRequest.newBuilder();
        builder.setValue(String.valueOf(tem));
        builder.setGuid("2222");
        builder.setTime(13456);
        connectManager.setAirAlgoValue(builder.build());
    }

    /**
     * 保存空调温度
     */
    private void saveTem(double recom,double current){
        RecommendEntity recommend = new RecommendEntity();
        if(current > recom){
            recom = current;
        }
        recommend.setCurrent_temp(current);
        recommend.setRecommend_temp(recom);
        recommend.setCollect_time(AlgoForecastTask.time);
        recommend.setAir_id("recom");
        recommendDAO.addRecommend(recommend);
    }

    /**
     * 空调告警
     * @param value
     */
    private void airWarn(double value){
        VerifyEdgePO verifyEdgePO = new VerifyEdgePO();
        verifyEdgePO.setValue(String.valueOf(value));
        verifyEdgePO.setType(1);
        warnService.verifyEdge(verifyEdgePO);
    }

    /**
     * 通过算法模型
     * @return
     */
    private double getRecomTempByAlgo(){
        //1.获取训练需要的服务器
        Map<String, String> map = recommendDAO.queryServersByPy();
        //2.将结果转化为json
        if(!map.containsKey("detail")){
            return -1;
        }
        String detail = map.get("detail");
        if(StringUtil.isEmpty(detail)){
            return -1;
        }
        Map servers = JSON.parseObject(detail, Map.class);
        Set<String> serverSns = servers.keySet();
        if (serverSns.size() == 0){
            return -1;
        }
        //3.调用训练接口
        return getTem(serverSns);
    }

    /**
     * 调用算法接口获取空调推荐温度
     * @return
     */
    private double getTem(Set<String> serverSns){
        StringBuffer servers = new StringBuffer();
        StringBuffer url = new StringBuffer();
        Map result = null;
        for(String sn : serverSns){
            servers.append(sn).append(",");
        }
        String sns = servers.substring(0, servers.length() - 1);
        url.append("http://")
            .append(aiIp)
            .append(":")
            .append(tempPreUrl)
            .append("&data=")
            .append(sns);
        String temUrl = url.toString();
        try {
            JSONObject request = HttpUtil.getRequest(temUrl);
            if(null == request){
                return -1;
            }
            result = request.toMap();
            if(null == result){
                 return -1;
             }
             if(result.get("err_code").equals(0)){
                 return Double.valueOf(result.get("data").toString());
             }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return -1;
    }
}
